package org.kgduyjj.toolkit.util;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;

/**
 * 集合工具类
 *
 * @author Kgduyjj
 */
public class CollectionUtils {
    protected static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];

    /**
     * 检查指定数组是否包含指定元素。
     *
     * @param array   被检查数组
     * @param element 要查找的对象
     * @param <T>
     * @return 如果找到返回 {@code true}，否则返回 {@code false}
     */
    public static <T> boolean contains(@Nullable T[] array, final T element) {
        if (array == null) {
            return false;
        }
        return Arrays.stream(array).anyMatch(x -> ObjectUtils.nullSafeEquals(x, element));
    }

    /**
     * Check whether the given Enumeration contains the given element.
     * 
     * @param enumeration the Enumeration to check
     * @param element     the element to look for
     * @return {@code true} if found, {@code false} otherwise
     */
    public static boolean contains(@Nullable Enumeration<?> enumeration, Object element) {
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                Object candidate = enumeration.nextElement();
                if (ObjectUtils.nullSafeEquals(candidate, element)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Check whether the given Iterator contains the given element.
     * 
     * @param iterator the Iterator to check
     * @param element  the element to look for
     * @return {@code true} if found, {@code false} otherwise
     */
    public static boolean contains(@Nullable Iterator<?> iterator, Object element) {
        if (iterator != null) {
            while (iterator.hasNext()) {
                Object candidate = iterator.next();
                if (ObjectUtils.nullSafeEquals(candidate, element)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 对象是否为数组对象
     *
     * @param obj 对象
     * @return 是否为数组对象，如果为{@code null} 返回false
     */
    public static boolean isArray(Object obj) {
        if (null == obj) {
            return false;
        }
        return obj.getClass().isArray();
    }

    /**
     * Return {@code true} if the supplied Collection is {@code null} or empty.
     * Otherwise, return {@code false}.
     * 
     * @param collection the Collection to check
     * @return whether the given Collection is empty
     */
    public static boolean isEmpty(@Nullable Collection<?> collection) {
        return (collection == null || collection.isEmpty());
    }

    /**
     * 判断指定集合是否不为空：即{@code null}或零长度。
     *
     * @param 要判定的集合
     * @return boolean
     */
    public static boolean notEmpty(@Nullable Collection<?> coll) {
        return !isEmpty(coll);
    }

    /**
     * Return {@code true} if the supplied Map is {@code null} or empty. Otherwise,
     * return {@code false}.
     * 
     * @param map the Map to check
     * @return whether the given Map is empty
     */
    public static boolean isEmpty(@Nullable Map<?, ?> map) {
        return (map == null || map.isEmpty());
    }

    /**
     * 判断指定Map是否为空：即{@code null}或长度为零。
     *
     * @param map the Map to check
     * @return boolean
     */
    public static boolean notEmpty(@Nullable Map<?, ?> map) {
        return !isEmpty(map);
    }

    /**
     * Convert the given array (which may be a primitive array) to an object array
     * (if necessary of primitive wrapper objects).
     * <p>
     * A {@code null} source value will be converted to an empty Object array.
     * 
     * @param source the (potentially primitive) array
     * @return the corresponding object array (never {@code null})
     * @throws IllegalArgumentException if the parameter is not an array
     */
    public static Object[] toObjectArray(@Nullable Object source) {
        if (source instanceof Object[]) {
            return (Object[]) source;
        }
        if (source == null) {
            return EMPTY_OBJECT_ARRAY;
        }
        if (!source.getClass().isArray()) {
            throw new IllegalArgumentException("Source is not an array: " + source);
        }
        int length = Array.getLength(source);
        if (length == 0) {
            return EMPTY_OBJECT_ARRAY;
        }
        Class<?> wrapperType = Array.get(source, 0).getClass();
        Object[] newArray = (Object[]) Array.newInstance(wrapperType, length);
        for (int i = 0; i < length; i++) {
            newArray[i] = Array.get(source, i);
        }
        return newArray;
    }

    /**
     * 判断数组集合为空
     * 
     * @param array
     * @return
     */
    public static boolean isEmpty(Object[] array) {
        if (array == null || Array.getLength(array) == 0) {
            return true;
        }
        return false;
    }

    /**
     * 判断数组集合不为空
     * 
     * @param array
     * @return
     */
    public static boolean notEmpty(Object[] array) {
        return !(isEmpty(array));
    }

    /**
     * Convert the supplied array into a List. A primitive array gets converted into
     * a List of the appropriate wrapper type.
     * <p>
     * <b>NOTE:</b> Generally prefer the standard {@link Arrays#asList} method. This
     * {@code arrayToList} method is just meant to deal with an incoming Object
     * value that might be an {@code Object[]} or a primitive array at runtime.
     * <p>
     * A {@code null} source value will be converted to an empty List.
     * 
     * @param source the (potentially primitive) array
     * @return the converted List result
     * @see ObjectUtils#toObjectArray(Object)
     * @see Arrays#asList(Object[])
     */
    @SuppressWarnings("rawtypes")
    public static List arrayToList(@Nullable Object source) {
        return Arrays.asList(ObjectUtils.toObjectArray(source));
    }

    public static <T> List<T> arrayToList(T[] array) {
        return Arrays.asList(array);
    }
}
